package com.example.goods.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.example.commons.analysis.ApiParse;
import com.example.commons.exception.BusinessException;
import com.example.commons.id.Serial;
import com.example.commons.redis.RedisKey;
import com.example.commons.redis.RedisLock;
import com.example.commons.redis.RedisLuaLock;
import com.example.commons.time.TimeTools;
import com.example.goods.mapper.OrdersMapper;
import com.example.goods.service.ArticleService;
import com.example.goods.service.OrdersService;
import com.example.goods.service.feign.UserAccountService;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.TimeUnit;

@Service
public class OrdersServiceImpl implements OrdersService {
    @Autowired
    ArticleService articleService;
    @Autowired
    OrdersMapper ordersMapper;
    @Autowired
    UserAccountService userAccountService;

    @Autowired
    RedisLock redisLock;
    @Autowired
    RedisLuaLock redisLuaLock;
    @Autowired
    RedissonClient redissonClient;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void order(String userId, String artId, int number) {
        this.business(artId, number, userId);
    }


    @Override
    @Transactional(rollbackFor = Exception.class)
    public void orderJedis(String userId, String artId, int number) {
        String uuid = UUID.randomUUID().toString().replace("-", "");
        try {
            if (redisLock.tryLock(RedisKey.ORDER.getRemarks(), uuid, 3000, 10000)) {
                //业务
                this.business(artId, number, userId);
            } else {
                throw new BusinessException("请求超时");
            }
        } catch (Exception e) {
            e.printStackTrace();
            if (e.getMessage().contains("库存不足")) {
                throw new BusinessException("库存不足");
            }
            throw new BusinessException("未知错误");
        } finally {
            redisLock.unlock(RedisKey.ORDER.getRemarks(), uuid);
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void orderJedisLua(String userId, String artId, int number) {
        String uuid = UUID.randomUUID().toString().replace("-", "");
        try {
            if (redisLuaLock.tryLock(RedisKey.ORDER.getRemarks(), uuid, 3000, 10000)) {
                //业务
                this.business(artId, number, userId);
            } else {
                throw new BusinessException("请求超时");
            }
        } catch (Exception e) {
            e.printStackTrace();
            if (e.getMessage().contains("库存不足")) {
                throw new BusinessException("库存不足");
            }
            throw new BusinessException("未知错误");
        } finally {
            redisLuaLock.unlock(RedisKey.ORDER.getRemarks(), uuid);
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void orderRedisson(String userId, String artId, int number) {
        RLock lock = redissonClient.getLock(RedisKey.ORDER.getRemarks());
        try {
            // lock.tryLock(30, 15, TimeUnit.SECONDS)：尝试加锁，最多等待 30 秒，上锁后 15 秒自动解锁
            //如果未指定锁的持有时间（即leaseTime参数为-1或未设置），则Redisson会自动开启看门狗机制。
            if (lock.tryLock(30, TimeUnit.SECONDS)) {
                //业务
                this.business(artId, number, userId);
            } else {
                throw new BusinessException("请求超时");
            }
        } catch (Exception e) {
            e.printStackTrace();
            if (e.getMessage().contains("库存不足")) {
                throw new BusinessException("库存不足");
            }
            throw new BusinessException("未知错误");
        } finally {
            lock.unlock();
        }
    }


    private void business(String artId, int number, String userId) {
        Map<String, Object> articleMap = articleService.selectArticleForUpdate(artId);
        if (1 != (int) articleMap.get("status")) {
            throw new BusinessException("商品已下架");
        }
        if (0 > ((int) articleMap.get("number") - number)) {
            throw new BusinessException("库存不足");
        }

        BigDecimal price = (BigDecimal) articleMap.get("price");
        try {
            if (1 != ordersMapper.addOrders(userId, Serial.getOrderId(userId), artId, price.toPlainString(), number, "下单", TimeTools.getTime())) {
                throw new BusinessException("下单失败");
            }
            articleService.updateOrderNumber(artId);
        } catch (Exception e) {
            e.printStackTrace();
            throw new BusinessException("下单失败");
        }

        //远程调用扣款
        JSONObject body = new JSONObject();
        body.put("userId", userId);
        body.put("balance", new BigDecimal(number).multiply(price).toPlainString());
        body.put("payType", 2);
        body.put("type", 1);
        body.put("remarks", "用户下单");
        body.put("explains", "用户下单说明");
        ApiParse.parse(userAccountService.operBal(body.toJSONString()));
    }
}
